/*

    tools23d - tools for converting images to 3D formats.
    Copyright (C) 2014  Dave Gorst

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

/**
@file   frameset.c
@brief  Manages a list of frames that will be used to determine which of the input files will be output at which time.
*/

#include <stdlib.h>
#include <time.h>

#include "tools23d.h"
#include "btime23d.h"
#include "frameset.h"
#include "util.h"

/**
@brief	Creating a frameset.

Create a list of frames that will be used to determine which of the
input files will be output at which time.

@param	cli_params	User-set options.
@param	number_of_input_files	Number of input files.
@param	framelist	Pointer to a list of pointers to frames.
@return	Number of frames contained in the newly created list.
*/

t3d_return T3D_CreateFrameset (params * cli_params, unsigned int number_of_input_files, unsigned int * framecount, frame_plan ** framelist)
{
	unsigned int list_frame;
	unsigned int sequence_frame;
	unsigned int total_number_of_displayed_frames;
	unsigned int each_repetition;
	unsigned int start_input_frame, end_input_frame;
	float frames_as_float;
	int temp_frame;
	unsigned int current_repetition;
	unsigned int write_frame = 0;

	if (((unsigned int) abs (cli_params->frame_offset) * 2) > number_of_input_files)
	{
		T3D_SetLastError ("Number off offset frames to remove (%d) is equal to or larger than the number of input files (%d).", abs (cli_params->frame_offset) * 2, number_of_input_files);
		return 0;
	}

	/* Round up to the next whole number. */
	frames_as_float =
		(!cli_params->wraparound ? number_of_input_files - (abs (cli_params->frame_offset) * 2) : number_of_input_files) *
		cli_params->time_stretch;
	each_repetition = frames_as_float != (float) ((int) frames_as_float) ? (int) frames_as_float + 1 : (int) frames_as_float;

	total_number_of_displayed_frames = each_repetition * cli_params->repetitions;

	start_input_frame = cli_params->wraparound ? 0 : abs (cli_params->frame_offset);
	end_input_frame = number_of_input_files - abs (cli_params->frame_offset);

	if ((*framelist = (frame_plan *) malloc (total_number_of_displayed_frames * sizeof (frame_plan))) != NULL)
	{
		for (current_repetition = 0; current_repetition < cli_params->repetitions; current_repetition++)
		{
			for (list_frame = start_input_frame; list_frame < end_input_frame; list_frame++)
			{
				sequence_frame = (unsigned int) ((float) (list_frame - start_input_frame) / cli_params->time_stretch);

				sequence_frame = T3D_GetDirectionFrame (cli_params->direction, current_repetition, sequence_frame, number_of_input_files);

				/* TODO sequence_frame *= sin (cli_params->sine) * total_number_of_frames; */

				(*framelist + write_frame)->left = sequence_frame;
				temp_frame = (*framelist + write_frame)->left + cli_params->frame_offset;

				if (temp_frame >= (int) number_of_input_files)
					temp_frame -= number_of_input_files;
				else if (temp_frame < 0)
					temp_frame += number_of_input_files;

				(*framelist + write_frame)->right = (unsigned int) temp_frame;
				write_frame++;
			}
		}

		*framecount = write_frame - 1;
	}
	else
		*framecount = 0;

	return *framecount != 0 ? t3d_success : t3d_operation_failed; 
}

/**
@brief	Destroy a previously created frameset.

@param	framelist	Pointer to a list of pointers to frames.
*/

void T3D_DestroyFrameset (frame_plan ** framelist)
{
	if (*framelist != NULL)
	{
		free (*framelist);
		*framelist = NULL;
	}
}

/**
@brief	Apply direction to frame number.

@param	my_direction	User-specified direction.
@param	repetition		How many times we have run through our input files?
@param	input_frame		The index of the current input frame.
@param	number_of_frames	Total number of frames in input set.
@return	New frame number after applying direction.
*/

unsigned int T3D_GetDirectionFrame (Directions my_direction, unsigned int repetition, unsigned int input_frame, unsigned int number_of_frames)
{
	switch (my_direction)
	{
	case Backwards:
		return number_of_frames - 1 - input_frame;
		break;
	case Bidirectional:
		if (repetition & 1)	return number_of_frames - input_frame - 1;
		break;
	default:
		/* As we're going forwards we don't need to do anything here. */
		break;
	}
	return input_frame;

}
